package model

import (
	"bytes"
	"errors"
	"fmt"
	."gitee.com/edgebox/pkg/process"
	"gorm.io/gorm/clause"
	"net/http"
	"os/exec"
	"reflect"
	"runtime"
	"time"
)
var shared_apps map[string]*App
func init_app(){
	shared_apps = make(map[string]*App)
	apps :=FindApps(&App{})
	for i:=0 ; i < len(apps); i++{
		id := apps[i].Id
		shared_apps[id] = &apps[i]
	}
	for _,v := range shared_apps{
		v.start()
	}
}
func httpPut(url string,data string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("exception:", r)
			err = errors.New("http put panic")
		}
	}()
	payload := bytes.NewBufferString(data)
	req, _ := http.NewRequest("PUT", url, payload)
	defer req.Body.Close()
	rq,_ := http.DefaultClient.Do(req)
	defer  rq.Body.Close()
	return nil
}
type App struct {
	Id       	string 		`xml:"-" json:"id" map:"id" gorm:"column:id;primary_key;not null;index"`
	Name     	string     	`xml:"-" json:"name" map:"name"`
	Path     	string		`xml:"-" json:"path" map:"path"`
	Args     	string 		`xml:"-" json:"args" map:"args"`
	No       	*int		`xml:"-" json:"no" map:"no"`
	Comments 	string 		`xml:"-" json:"comments" map:"comments"`
	Status   	string		`xml:"-" json:"-" map:"status" gorm:"-"`
	Pid 	 	int			`xml:"-" json:"-" map:"pid" gorm:"-"`
	StartTime  	string		`xml:"-" json:"-" map:"startTime" gorm:"-"`
	DuringTime 	int64		`xml:"-" json:"-" map:"duringTime" gorm:"-"`
	proc     	*Process	`xml:"-" json:"-" map:"-" gorm:"-"`
}
func FindApps(filter *App)[]App{
	var apps []App
	if err:=sqldb.Find(&apps,filter).Error;err != nil{
		return nil
	}else{
		return apps
	}
}
func DeleteApps()(int64,error){
	var apps []App
	sqldb.Find(&apps)
	index :=0
	for i:=0; i < len(apps); i++{
		if _,err := apps[i].Delete();err != nil{
			return int64(index),err
		}
		index += 1
	}
	return int64(index),nil
}

func killProcess(text string){
	sysType := runtime.GOOS
	if sysType != "linux" {
		cmd:= exec.Command("taskkill", "/f", "/t", "/im", text)
		_, err := cmd.CombinedOutput()
		if err != nil{
			fmt.Println(err)
		}

	}
}

func (p* App) Insert()error{
	return sqldb.Create(p).Error
}
func (p* App) Save()(int64,error){
	ret := sqldb.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "id"}},
		DoUpdates: clause.AssignmentColumns([]string{"name", "path","args","no","comments"}),
	}).Create(p)
	return ret.RowsAffected,ret.Error
}
func (p* App) Delete()(int64,error){
	db :=sqldb.Where(&App{Id:p.Id}).Delete(&App{})
	return db.RowsAffected,db.Error
}
func (s* App) Restart()error{
	p := shared_apps[s.Id]
	if *p.No <= 0{
		return nil
	}
	sysType := runtime.GOOS
	if sysType == "linux" {
		p.stop()
		p.start()
	}else{
		//cmd :=make(map[string]string)
		//cmd["Cmd"] = "exit"
		//data,_:=json.Marshal(cmd)
		p.stop()
		killProcess(s.Name + ".exe")
		//httpPut("http://127.0.0.1:" + strconv.Itoa(*s.No) + "/exit",string(data))
		p.start()
	}
	return nil
}
func (s* App) Update()error{
	p := shared_apps[s.Id]
	if p.proc == nil{
		p.Pid = -1
		p.Status = "app not found"
	}else{
		p.Pid = p.proc.Pid()
		if p.Pid > 0 {
			p.Status = "running"
		}else{
			p.Status = "stopped"
		}
	}
	return nil
}
func (p* App) start()error{
	if *p.No < 0{
		return nil
	}
	if p.proc != nil{
		go p.proc.Start()

	}else{
		p.proc = NewProcess(p.Id,p.Path,p.Args)
		go p.proc.Start()
	}
	p.StartTime = time.Now().Format("2006-01-02 15:04:05")
	return nil
}
func (p* App) stop()error{
	if *p.No < 0{
		return nil
	}
	if p.proc != nil{
		p.proc.Stop()
	}
	return nil
}
func(p* App)ToMap()map[string]interface{}{
	obj := p
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)
	if t.Kind() == reflect.Ptr { // 如果是指针，则获取其所指向的元素
		t = t.Elem()
		v = v.Elem()
	}
	var data = make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		tagName := t.Field(i).Tag.Get("map")
		if tagName != "" && tagName != "-" {
			data[tagName] = v.Field(i).Interface()
		}
	}
	return data
}